import Cookies from 'js-cookie'
import md5 from 'js-md5'

/** 设置 localStorage 添加对时间的控制，hour单位为小时
 * hour=null时使用原始sessionStorage(key,value两个参数默认为session)，即关闭浏览器过期
 * hour=0时，使用localStorage，即永不过期
 * hour>0时添加时间控制，即指定过期时间，类似于cookies
 * */

// 设置缓存
export function setStorage(key, value, hour) {
  if (hour === 0) {
    window.localStorage.setItem(key, JSON.stringify(value))
  } else if (hour === undefined) {
    window.sessionStorage.setItem(key, JSON.stringify(value))
  } else if (hour > 0) {
    const now = new Date()
    const valueDate = JSON.stringify({
      value,
      time: now.setSeconds(now.getSeconds() + hour * 3600)
    })
    window.localStorage.setItem(key, valueDate)
  }
}

/** 获取 Storage
* 一个参数key默认为sessionStorage
* 两个参数key,any任意值为localStorage
* */
export function getStorage(key, any) {
  if (any === undefined) {
    const val = window.sessionStorage.getItem(key)
    if (val) {
      return JSON.parse(val)
    }
    return val
  }
  const now = new Date()
  const local = window.localStorage.getItem(key)
  if (local) {
    let dataObj = ''
    try {
      dataObj = JSON.parse(local)
    } catch (e) {
      dataObj = local
    }
    if (dataObj.time) {
      // 存在时间值，则判断是否过期
      if (now < new Date(dataObj.time)) {
        // 在当前时间后，表示没过期
        return dataObj.value
      }
      // 如果时间过期了，返回空值，并清空
      window.localStorage.removeItem(key)
      return null
    }
    return dataObj
  }
  return local
}

// clear localStorage
export function clearStorage() {
  window.localStorage.clear()
}

/** 移除 Storage
* 一个参数key默认为sessionStorage
* 两个参数key,any任意值为localStorage
* */
export function removeStorage(key, any) {
  if (any === undefined) {
    window.sessionStorage.removeItem(key)
  } else {
    window.localStorage.removeItem(key)
  }
}

const isCompleteDataType = (item) => (typeof item === 'object' && typeof item !== 'function') && (item !== null)
/** 深度复制数组 */
export function deepCopy(obj, hash = new WeakMap()) { // 使用hashWeak解决循环引用的问题
  if (obj.constructor === Date) return new Date(obj)
  if (obj.constructor === RegExp) return new RegExp(obj)
  if (hash.has(obj)) {
    return hash.get(obj)
  }
  const allDesc = Object.getOwnPropertyDescriptors(obj) // 获取当前对象的所有详情描述
  const cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
  hash.set(obj, cloneObj)
  Object.keys(obj).forEach((key) => {
    const element = obj[key]
    cloneObj[key] = isCompleteDataType(element) ? deepCopy(element, hash) : obj[key]
  })
  return cloneObj
}

/** 获取token ,两种token ，bool为真时为refreshToken */
export function getToken(bool) {
  const key = bool ? 'refreshToken' : 'token'
  return getStorage(key, 0) // 带时间保存的
}

/** 设置 token 及过期时间 */
// hour保存的小时
export function setToken(token, hour, bool) {
  if (!token) {
    return
  }
  let key = 'token'
  let expires = hour
  if (bool) {
    key = 'refreshToken'
    expires = hour * 2
  }
  setStorage(key, token, expires)
}

export function removeToken(bool) {
  const key = bool ? 'refreshToken' : 'token'
  removeStorage(key, 0)
}

// cookies方法：获取cookies
export function getCookies(key) {
  return Cookies.get(key)
}

// 设置cookies
export function setCookies(key, value, time) {
  return Cookies.set(key, value, { expires: time })
}

// 移除cookies
export function removeCookies(key) {
  return Cookies.remove(key)
}

// 获取headers
export function getHeaders(api, token) {
  if (!token) {
    token = getToken() || ''
  }
  if (!api) {
    api = ''
  }
  let tokenApiTimer = md5(token + api + new Date().getTime()) // 返回token+api+timer
  tokenApiTimer = tokenApiTimer.substr(0, 16) // 16位

  return {
    Authorization: token,
    'X-B3-TraceId': tokenApiTimer,
    'X-B3-SpanId': tokenApiTimer
  }
}

// 防抖
export function debounce(fn, delay = 500) {
  let timer
  return function (...args) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, delay)
  }
}

// 节流
export function throttle(fn, delay = 500) {
  let canUse = true // 设置一个开关
  return function () {
    if (!canUse) {
      return false // 如果开关已经关掉了就不用往下了
    }
    canUse = false // 利用闭包刚进来的时候关闭开关
    setTimeout(() => {
      fn.apply(this, arguments)
      canUse = true // 执行完才打开开关
    }, delay)
  }
}
